// 模拟实现Promise
// Promise利用三大手段解决回调地狱：
// 1. 回调函数延迟绑定
// 2. 返回值穿透
// 3. 错误冒泡

// 定义三种状态
const PENDING = 'PENDING'; // 进行中
const FULFILLED = 'FULFILLED'; // 已成功
const REJECTED = 'REJECTED'; // 已失败

class Promise {
	constructor(exector) {
		// 初始化状态
		this.status = PENDING;
		// 将成功、失败结果放在this上，便于then、catch访问
		this.value = undefined;
		this.reason = undefined;
		// 成功态回调函数队列
		this.onFulfilledCallbacks = [];
		// 失败态回调函数队列
		this.onRejectedCallbacks = [];

		const resolve = (value) => {
			// 只有进行中状态才能更改状态
			if (this.status === PENDING) {
				this.status = FULFILLED;
				this.value = value;
				// 成功态函数依次执行
				this.onFulfilledCallbacks.forEach((fn) => fn(this.value));
			}
		};
		const reject = (reason) => {
			// 只有进行中状态才能更改状态
			if (this.status === PENDING) {
				this.status = REJECTED;
				this.reason = reason;
				// 失败态函数依次执行
				this.onRejectedCallbacks.forEach((fn) => fn(this.reason));
			}
		};
		try {
			// 立即执行executor
			// 把内部的resolve和reject传入executor，用户可调用resolve和reject
			exector(resolve, reject);
		} catch (e) {
			// executor执行出错，将错误内容reject抛出去
			reject(e);
		}
	}
	then(onFulfilled, onRejected) {
		onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
		onRejected =
			typeof onRejected === 'function'
				? onRejected
				: (reason) => {
						throw new Error(reason instanceof Error ? reason.message : reason);
					};
		// 保存this
		const self = this;
		return new Promise((resolve, reject) => {
			if (self.status === PENDING) {
				self.onFulfilledCallbacks.push(() => {
					// try捕获错误
					try {
						// 模拟微任务
						setTimeout(() => {
							const result = onFulfilled(self.value);
							// 分两种情况：
							// 1. 回调函数返回值是Promise，执行then操作
							// 2. 如果不是Promise，调用新Promise的resolve函数
							result instanceof Promise ? result.then(resolve, reject) : resolve(result);
						});
					} catch (e) {
						reject(e);
					}
				});
				self.onRejectedCallbacks.push(() => {
					// 以下同理
					try {
						setTimeout(() => {
							const result = onRejected(self.reason);
							// 不同点：此时是reject
							result instanceof Promise ? result.then(resolve, reject) : resolve(result);
						});
					} catch (e) {
						reject(e);
					}
				});
			} else if (self.status === FULFILLED) {
				try {
					setTimeout(() => {
						const result = onFulfilled(self.value);
						result instanceof Promise ? result.then(resolve, reject) : resolve(result);
					});
				} catch (e) {
					reject(e);
				}
			} else if (self.status === REJECTED) {
				try {
					setTimeout(() => {
						const result = onRejected(self.reason);
						result instanceof Promise ? result.then(resolve, reject) : resolve(result);
					});
				} catch (e) {
					reject(e);
				}
			}
		});
	}
	catch(onRejected) {
		return this.then(null, onRejected);
	}
	static resolve(value) {
		if (value instanceof Promise) {
			// 如果是Promise实例，直接返回
			return value;
		} else {
			// 如果不是Promise实例，返回一个新的Promise对象，状态为FULFILLED
			return new Promise((resolve, reject) => resolve(value));
		}
	}
	static reject(reason) {
		return new Promise((resolve, reject) => {
			reject(reason);
		});
	}
	static all(promiseArr) {
		const len = promiseArr.length;
		const values = new Array(len);
		// 记录已经成功执行的promise个数
		let count = 0;
		return new Promise((resolve, reject) => {
			for (let i = 0; i < len; i++) {
				// Promise.resolve()处理，确保每一个都是promise实例
				Promise.resolve(promiseArr[i]).then(
					(val) => {
						values[i] = val;
						count++;
						// 如果全部执行完，返回promise的状态就可以改变了
						if (count === len) resolve(values);
					},
					(err) => reject(err)
				);
			}
		});
	}
	static race(promiseArr) {
		return new Promise((resolve, reject) => {
			promiseArr.forEach((p) => {
				Promise.resolve(p).then((val) => resolve(val), (err) => reject(err));
			});
		});
	}
}

// 实现有并行限制的Promise
// Promise调度
class Scheduler {
	constructor() {
		this.queue = [];
		this.maxCount = 2;
		this.runCounts = 0;
	}
	add(promiseCreator) {
		this.queue.push(promiseCreator);
	}
	taskStart() {
		for (let i = 0; i < this.maxCount; i++) {
			this.request();
		}
	}
	request() {
		if (!this.queue || !this.queue.length || this.runCounts >= this.maxCount) {
			return;
		}
		this.runCounts++;

		this.queue.shift()().then(() => {
			this.runCounts--;
			this.request();
		});
	}
}

const timeout = (time) =>
	new Promise((resolve) => {
		setTimeout(resolve, time);
	});

const scheduler = new Scheduler();

const addTask = (time, order) => {
	scheduler.add(() => timeout(time).then(() => console.log(order)));
};

addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// scheduler.taskStart();
// 2
// 3
// 1
// 4

// 顺序调用promise
const prom1 = a => {
	return new Promise((resolve => {
		resolve(a)
	}))
}
const prom2 = a => {
	return new Promise((resolve => {
		setTimeout(() => {
			resolve(a * 2)
		}, 3000);
	}))
}
const prom3 = a => {
	return new Promise((resolve => {
		resolve(a * 3)
	}))
}

const arr = [prom1, prom2, prom3]
const result = arr.reduce((all, current) => {
	return all.then(current)
}, Promise.resolve(10))

result.then(res => {
	console.log(res);
})

function digui(arr, res = '') {
	if (arr.length === 0) {
		console.log(res);
		return res
	}
	arr.shift()(res).then(res => {
		console.log('digui', res);
		digui(arr, res)
	})
}
console.log(digui(arr, 10));
